﻿// Copyright (c) Appeon. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. 
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.

using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace SnapObjects.Data.Odbc
{
    internal class OdbcHanaSqlColumnSchemaProvider : SqlColumnSchemaProvider
    {
        public OdbcHanaSqlColumnSchemaProvider(DataContext dataContext) : base(dataContext)
        {
        }

        protected override bool IsExtraHandleNullable => true;

        public override IReadOnlyList<DbColumnInfo> GetColumnSchema(string sqlText, IEnumerable<IAdoDbParameter> parameters)
        {
            var columnSchema = base.GetColumnSchema(sqlText, parameters);

            this.ExtraHandleSchemaName(sqlText, columnSchema);

            return columnSchema;
        }

        public async override Task<IReadOnlyList<DbColumnInfo>> GetColumnSchemaAsync(string sqlText, IEnumerable<IAdoDbParameter> parameters, CancellationToken cancellationToken)
        {
            var columnSchema = await base.GetColumnSchemaAsync(sqlText, parameters, cancellationToken);

            this.ExtraHandleSchemaName(sqlText, columnSchema);

            return columnSchema;
        }

        protected override bool IsIdentity(DataRow row, IDataReader reader)
        {
            var column = row.Table.Columns["isautoincrement"];

            var value = row.ItemArray[column.Ordinal];

            return this.GetSchemaItemValue<bool>(value);
        }

        protected override bool IsExpression(DataRow row, IDataReader reader)
        {
            var isReadOnly = this.IsReadOnly(row, reader);

            var tableName = this.ColumnTableName(row, reader);

            if (!isReadOnly && String.IsNullOrWhiteSpace(tableName))
            {
                isReadOnly = true;
            }

            return isReadOnly;
        }

        protected override bool IsHidden(DataRow row, IDataReader reader)
        {
            return false;
        }

        protected override string ColumnDataTypeName(DataRow row, IDataReader reader)
        {
            var ordinal = this.ColumnOrdinal(row, reader);

            if (reader != null)
            {
                return reader.GetDataTypeName(ordinal);
            }

            return null;
        }

        protected override bool IsReadOnly(DataRow row, IDataReader reader)
        {
            var column = row.Table.Columns["isreadonly"];

            var value = row.ItemArray[column.Ordinal];

            return this.GetSchemaItemValue<bool>(value); 
        }

        private void ExtraHandleSchemaName(string sqlText, IReadOnlyList<DbColumnInfo> dbColumnInfos)
        {
            try
            {
                var dic = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

                var factory = _dataContext.AdoDbSqlProvider.SqlStatementFactory;

                var sqlParser = factory.GetSqlParser(SqlStatementType.Select);

                var sqlSelect = (SqlSelectStatement)sqlParser.Parse(sqlText);

                var isMultiTable = sqlSelect.From.Exists(m => m.IsCharacter(SqlCharacters.Comma));

                foreach (var column in dbColumnInfos)
                {
                    if (!String.IsNullOrWhiteSpace(column.Table))
                    {
                        for (var i = 0; i < sqlSelect.From.Count; i++)
                        {
                            if (column.Table.Equals(
                                sqlSelect.From[i].Text, StringComparison.OrdinalIgnoreCase) &&
                                i > 1 && 
                                ".".Equals(sqlSelect.From[i-1].Text))
                            {
                                column.TableSchema = sqlSelect.From[i - 2].Text;
                            }
                        }
                    }
                }
            }
            catch
            {
                //TODO:    
            }
        }
    }
}
